using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using System.Text;
using IReaper.Properties;

namespace IReaper.Initializer
{
    /// <summary>
    /// User HTTP Conditional Get to get latest info.xml
    /// </summary>
    public class CheckInfoXMLTask : AbstractInitTask
    {
        private static DateTime MinValue = new DateTime(1970, 1, 1);

        HttpWebRequest request;
        HttpWebResponse response;
        FileStream fsStream;

        protected override void JobContent()
        {
            try
            {
                //set message
                this.InitManager.SetMessage(StringResources.Checking +
                                            DataFileName +
                                            StringResources.LastModifiedDate);
                if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
                { return; }
                DateTime localDate = this.LastModifiedDate();
                this.ConditionalGet(localDate);
            }
            catch (Exception e)
            {
                InitManager.SetException(e);
            }
            finally
            {
                //make sure the resources are closed.
                if (response != null)
                    response.Close();
                if (fsStream != null)
                    fsStream.Close();
            }
        }

        /// <summary>
        /// Check the last modified date of info.xml
        /// </summary>
        /// <returns>last modified date</returns>
        private DateTime LastModifiedDate()
        {
            //get file information
            FileInfo fileInfo = new FileInfo(DataFileName);
            DateTime LocalTime;
            if (!fileInfo.Exists)//if file is not found, set the DateTime.MinValue as time
            {
                this.InitManager.SetMessage(StringResources.FileNotFound + " " + DataFileName);
                LocalTime = MinValue;
            }
            else
                LocalTime = fileInfo.LastWriteTime;//otherwise,get the datetime
            return LocalTime;
        }

        /// <summary>
        /// Use conditional get to download info.xml
        /// </summary>
        /// <param name="LocalDate">last modified date of local info.xml</param>
        private void ConditionalGet(DateTime LocalDate)
        {
            string path = Settings.Default.PathBase + DataFileName;
            //create HttpWebRequest
            request = (HttpWebRequest)WebRequest.Create(path);
            request.IfModifiedSince = LocalDate;
            request.ReadWriteTimeout = 1; // fix 304 no response problem
            //try to get response
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (Exception e) //For some reason the HttpWebResponse class throws an exception on 3xx responses
            {
                WebException we = e as WebException;
                if ( we != null && we.Response != null)
                {
                    response = (HttpWebResponse)we.Response;
                }
                else
                {
                    throw;
                }
            }
            //if responseCode is 304,which means no need to update.
            if (response.StatusCode == HttpStatusCode.NotModified)//check if not modified
            {
                response.Close();
                this.resultObj = "NotModified";
                return;
            }
            //if means there is something mistake.
            else if (response.ContentLength == -1)
            {
                throw new ApplicationException(StringResources.ERROR_GetInfoXML + response.StatusDescription + "(" + response.StatusCode.ToString() + ")");
            }
            else if(response.ContentType == "text/xml") //the info.xml is updated since last time
            {
                
                //set message
                this.InitManager.SetMessage(StringResources.BeginDownload + DataFileName);
                //get last modified date of 
                DateTime LastModified = response.LastModified;
                //get the network stream
                Stream netStream = response.GetResponseStream();
                //create the info.xml local stream
                try
                {
                    fsStream = new FileStream("./info.xml.temp", FileMode.Create, FileAccess.Write, FileShare.None);
                    //set the creation time as minValue in case the download is interrputed.

                    //download
                    long length = response.ContentLength;
                    byte[] buffer = new byte[1024];
                    fsStream.SetLength(response.ContentLength);
                    int iRead = 0;
                    while (fsStream.Position < length)
                    {
                        iRead = netStream.Read(buffer, 0, 1024);
                        fsStream.Write(buffer, 0, iRead);
                        //set message
                        int percentage = (int)(fsStream.Position * 100 / length);
                        this.InitManager.SetMessage(StringResources.Downloading + percentage.ToString() + "%");
                    }
                    fsStream.Close();
                }
                catch
                {
                    //close the stream to set the last write time
                    fsStream.Close();
                    throw;
                }
                finally
                {
                    netStream.Close();
                }
                File.Delete("./info.xml");
                File.Move("./info.xml.temp", "./info.xml");
                File.SetLastWriteTime("./info.xml", LastModified);
                //set message
                this.resultObj = "Modified";
            }
        }
    }
}
